package cn.t.keycloak.plugin.login.mfa;

import lombok.extern.slf4j.Slf4j;
import org.keycloak.Config;
import org.keycloak.authentication.Authenticator;
import org.keycloak.authentication.AuthenticatorFactory;
import org.keycloak.models.AuthenticationExecutionModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.provider.ProviderConfigProperty;

import java.util.List;

/**
 * 自定义一个认证工厂(SMS)
 * AuthenticatorFactory也是继承的ProviderFactory,基本原理都是一样的
 * @author 陶敏麒
 * @date 2023/11/15 14:27
 */
@Slf4j
public class SmsMfaAuthenticatorFactory implements AuthenticatorFactory {

    // 单例
    private static final SmsMfaAuthenticator SINGLETON = new SmsMfaAuthenticator();

    public static final String PROVIDER_ID = "sms-authenticator";

    /**
     * 在控制台的描述
     */
    @Override
    public String getDisplayType() {
        return "手机验证码MFA认证";
    }

    /**
     * 帮助文本
     */
    @Override
    public String getHelpText() {
        return "手机验证码认证";
    }

    /**
     * 当前认证所属的类别(在控制台显示,可自定义)
     */
    @Override
    public String getReferenceCategory() {
        return "sms auth";
    }

    /**
     * 是否是可配置的,可以在控制台或者API配置,false表示行为固定不可修改
     */
    @Override
    public boolean isConfigurable() {
        return true;
    }

    // 子流程必须使用CONDITIONAL，而认证器的需求应该是REQUIRED、CONDITIONAL和DISABLED中任意一种，除非有特殊需求
//    private static AuthenticationExecutionModel.Requirement[] REQUIREMENT_CHOICES = {
//            AuthenticationExecutionModel.Requirement.REQUIRED,
//            AuthenticationExecutionModel.Requirement.ALTERNATIVE,
//            AuthenticationExecutionModel.Requirement.DISABLED
//    };

    /**
     * 认证类型(必须、可选、禁用)
     */
    @Override
    public AuthenticationExecutionModel.Requirement[] getRequirementChoices() {
        return REQUIREMENT_CHOICES;
    }

    /**
     * tells the flow manager whether or not
     * Authenticator.setRequiredActions() method will be called.
     * 认证器没有配置给用户时,流程会抛出异常并终止,为true时会调用Authenticator.setRequiredActions().
     */
    @Override
    public boolean isUserSetupAllowed() {
        return true;
    }

    @Override
    public List<ProviderConfigProperty> getConfigProperties() {
        // 可以在这里自定义的表单配置的认证属性,服务会根据传入的类别自动渲染为单选框、输入框
        return List.of(
                new ProviderConfigProperty(SmsProperties.SMS_ENABLE, "是否启用手机验证码登录", "是否启用手机验证码登录，不启用将以用户名密码登录", ProviderConfigProperty.BOOLEAN_TYPE, false),
                new ProviderConfigProperty(SmsProperties.SMS_DEBUG_MODE, "调试模式", "调试模式中输入指定的验证码即可完成认证", ProviderConfigProperty.BOOLEAN_TYPE, false),
                new ProviderConfigProperty(SmsProperties.SMS_DEBUG_MODE_VALUE, "调试模式验证码", "指定调试模式验证码", ProviderConfigProperty.TEXT_TYPE, "8888")
        );
    }

    @Override
    public String getId() {
        return PROVIDER_ID;
    }
    // 返回单例
    @Override
    public Authenticator create(KeycloakSession keycloakSession) {
        return SINGLETON;
    }

    @Override
    public void init(Config.Scope scope) {
        log.info("SmsAuthenticatorFactory开始加载");
    }
    @Override
    public void postInit(KeycloakSessionFactory keycloakSessionFactory) {}
    @Override
    public void close() {}
}
